using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Rainbow.ObjectFlow.Framework;

namespace TestDoc
{
    internal class ParseConfiguration : BasicOperation<Program.TestReport>
    {
        private const string MessageHelp = "TestDoc.Messages.Help.txt";
        private const string ErrorMissingCommandLineArguments = "Error: Missing command line arguments\r\n";
        private const string ErrorFileNotFound = "Error: File not found or is invalid";

        public override Program.TestReport Execute(Program.TestReport data)
        {
            data.Properties = ParseArguments(data.Arguments);

            if (!CommanlineArgumentsAreValid(data.Assembly,data.Properties))
            {
                SetSuccessResult(false);
            }

            return data;
        }

        private static Program.CommandLineArguments ParseArguments(ICollection<string> commandLineArguments)
        {

            IDictionary<string, string> splitArguments = new CommandLine(commandLineArguments).Parse().Arguments;

            var arguments = new Program.CommandLineArguments();
            if (HasArguments(splitArguments))
            {
                foreach (var argument in splitArguments)
                {
                    if (argument.Key == "-f")
                    {
                        arguments.File = argument.Value;
                    }
                }
            }
            return arguments;
        }

        private static bool CommanlineArgumentsAreValid(Assembly thisExe, Program.CommandLineArguments commandLine)
        {
            bool isValid = IsValid(commandLine);
            if (!isValid)
            {
                DisplayError(thisExe, ErrorMissingCommandLineArguments);
                return false;
            }

            if (!AssemblyFileExists(commandLine.File))
            {
                DisplayError(thisExe, ErrorFileNotFound);
                return false;
            }

            return true;
        }

        private static bool HasArguments(ICollection<KeyValuePair<string, string>> arguments)
        {
            return arguments != null && arguments.Count > 0;
        }

        private static bool IsValid(Program.CommandLineArguments commandLine)
        {
            return !string.IsNullOrEmpty(commandLine.File);
        }

        private static bool AssemblyFileExists(string assemblyName)
        {
            return assemblyName != string.Empty && File.Exists(assemblyName);
        }

        // REVIEW: Duplicates
        private static void DisplayError(Assembly thisExe, string error)
        {
            Console.WriteLine(error);
            PrintHelpFile(thisExe);
        }

        private static void PrintHelpFile(Assembly thisExe)
        {
            string headerText = GetResourceText(thisExe, MessageHelp);
            Console.WriteLine(headerText);
        }

        private static string GetResourceText(Assembly thisExe, string resourceName)
        {
            string headerText;
            using (var header = thisExe.GetManifestResourceStream(resourceName))
            {
                Debug.Assert(header != null, "Cannot resolve resource");

                using (TextReader reader = new StreamReader(header))
                {
                    headerText = reader.ReadToEnd();
                }
            }
            return headerText;
        }

    }
}